package com.my.juc.readwrite;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author zhupanlin
 * @version 1.0
 * @description: TODO
 * @date 2024/3/6 14:47
 */

/**
 * 读写锁 可以多人同时进行读操作
 * 缺点：1) 造成锁饥饿，一直读，没有写操作
 *      2)读的时候不能写，写的时候不能读
 */

// 资源类
class MyCache{
    // 创建map集合
    private volatile Map<String, Object> map = new HashMap<>();
    
    // 创建读写锁对象
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();
    
    // 放数据
    public void put(String key, Object value){
        // 添加写锁
        Lock lock = rwLock.writeLock();
        lock.lock();
        System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName() + "正在写操作" + key);
        
        // 暂停
        try {
            TimeUnit.MICROSECONDS.sleep(300);
            // 放数据
            map.put(key, value);

            System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName() + "写完了" + key);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            // 释放写锁
            lock.unlock();
        }
        
        

    }
    
    // 取数据
    public Object get(String key){
        // 添加读锁
        Lock lock = rwLock.readLock();
        lock.lock();
        Object res = null;
        System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName() + "正在读数据" + key);
        // 暂停
        try {
            TimeUnit.MICROSECONDS.sleep(300);
            res = map.get(key);

            System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName() + "已经取完了" + res);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            lock.unlock();
        }
        return res; 

    }
}

public class ReadWriterLockDemo {

    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        // 创建线程放数据
        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(() -> {
                myCache.put(num + "", num + "");
            }, i + "").start();
        }

        // 创建线程放数据
        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(() -> {
                System.out.println("myCache.get(num + \"\") = " + myCache.get(num + ""));
            }, i + "").start();
        }
    }
    
}
